/*
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements.  See the NOTICE file
distributed with this work for additional information
regarding copyright ownership.  The ASF licenses this file
to you under the Apache License, Version 2.0 (the
"License"); you may not use this file except in compliance
with the License.  You may obtain a copy of the License at

http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing,
software distributed under the License is distributed on an
"AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
KIND, either express or implied.  See the License for the
specific language governing permissions and limitations
under the License.
 */
package td.server;

import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Date;
import java.util.List;
import java.util.UUID;
import java.util.regex.Pattern;

import td.domain.Thinker;
import td.domain.util.IdCache;
import td.domain.util.LoadGroup;
import td.server.ServerConstants.ENTITY;
import td.server.dao.ObjectifyDao;
import td.server.dao.ThinkerDao;
import td.shared.Constants;
import td.shared.TooManyResultsException;

import com.google.inject.Inject;

/**
 * @author Artem Shamsutdinov
 * 
 */
public class LoginService {
	private static final Pattern PATTERN = Pattern
			.compile(Constants.PASSWORD_PATTERN);

	@Inject
	ThinkerDao thinkerDao;

	@Inject
	ObjectifyDao<IdCache> idCacheDao;

	@SuppressWarnings("unchecked")
	public Thinker findThinkerByEmail(String thinkerEMail) {
		Thinker thinker = null;
		try {
			thinker = thinkerDao.getByProperty(ENTITY.THINKER.EMAIL,
					thinkerEMail);
		} catch (TooManyResultsException tmre) {
			throw new RuntimeException(tmre);
		}
		return thinker;
	}

	public Thinker findThinkerById(String thinkerId,
			Class<? extends LoadGroup>... loadGroups) {
		Thinker thinker = null;
		try {
			thinker = thinkerDao.getByProperty(ENTITY.THINKER.ID, thinkerId,
					loadGroups);
		} catch (TooManyResultsException tmre) {
			throw new RuntimeException(tmre);
		}
		return thinker;
	}

	public Thinker addThinker(String email, String thinkerId, String password) {
		return null;
		// FIXME: add this back in and figure out how to deal with Ref in GWT
		// String passwordDigest = generateHash(password);
		// Thinker newThinker = new Thinker(email, thinkerId, passwordDigest,
		// new Date());
		// String sessionCode = UUID.randomUUID().toString();
		// newThinker.setSessionCode(sessionCode);
		// newThinker.setLastAccessDate(new Date());
		//
		// IdCache recentPublishedThoughtIds = new IdCache();
		// Key<IdCache> publishedIdsKey =
		// idCacheDao.putNow(recentPublishedThoughtIds);
		// IdCache recentUnpublishedThoughtIds = new IdCache();
		// Key<IdCache> unpublishedIdsKey = idCacheDao
		// .putNow(recentUnpublishedThoughtIds);
		// newThinker.setRecentPublishedThoughtIds(Ref.create(publishedIdsKey));
		// newThinker.setRecentUnpublishedThoughtIds(Ref.create(unpublishedIdsKey));
		// thinkerDao.putNow(newThinker);
		// return newThinker;
	}

	public String updateSessionCode(Thinker thinker) {
		String sessionCode = UUID.randomUUID().toString();
		thinker.setSessionCode(sessionCode);
		thinker.setLastAccessDate(new Date());
		thinkerDao.put(thinker);
		return sessionCode;
	}

	public boolean isCorrectPassword(Thinker thinker, String password) {
		String passwordDigest = generateHash(password);
		return thinker.getPasswordDigest().equals(passwordDigest);
	}

	public boolean isValidPassword(String password) {
		return LoginService.PATTERN.matcher(password).matches();
	}

	@SuppressWarnings("unchecked")
	public List<Thinker> getAllThinkers() {
		return thinkerDao.listAll();
	}

	public void save(Thinker thinker) {
		thinkerDao.put(thinker);
	}

	// TODO: return a readable string representation
	private String generateHash(String password) {
		try {
			byte[] bytesOfMessage = password.getBytes("UTF-8");
			MessageDigest md = MessageDigest.getInstance("MD5");
			byte[] theDigest = md.digest(bytesOfMessage);
			return new String(theDigest);
		} catch (UnsupportedEncodingException e) {
		} catch (NoSuchAlgorithmException e) {
		}
		return null;
	}

}
